/*
 * framework.cpp
 *
 *  Created on: Sep 9, 2008
 *      Author: andreevm
 *
 *  Framework for processing network data
 *  according to "Many Connections / Many Threads"
 *  strategy.
 */

#include <framework.hpp>

class connection : /* allow to get shared_ptr to object from
					  within member function */
	public boost::enable_shared_from_this<connection> {
public:
    typedef boost::shared_ptr<connection> pointer;

    /**
     * Create new connection
     *
     * @param io_service io_service in which this connection will work
     *
     * @return pointer to newly allocated object
     */
    static pointer create(asio::io_service& io_service) {
        return pointer(new connection(io_service));
    }

    /**
     * Return socket, associated with this connection. This socket used in accept operation
     *
     *
     * @return reference to socket
     */
    asio::ip::tcp::socket& socket() {
        return socket_;
    }

    /*
     * Start input/output chain with reading of headers from browser
     *
     */
    void start() {
        // start reading of headers from browser
        /*asio::async_read_until(socket_, buf, boost::regex("\r\n\r\n"),
            boost::bind(&connection::handle_read, shared_from_this(),
                        asio::placeholders::bytes_transferred));*/
    }

private:
    /**
     * Initialize connection
     *
     * @param io_service
     *
     * @return
     */
    connection(asio::io_service& io_service) : socket_(io_service) {
    }

    /**
     * Called when data written to browser
     *
     * @param error object, containing information about errors
     * @param bytes_transferred number of transferred bytes
     */
    void handle_write(size_t bytes_transferred) {
    }

    /**
     * Called when data readed from browser
     *
     * @param error object, containing information about errors
     * @param bytes_transferred number of transferred bytes
     */
    void handle_read(size_t bytes_transferred) {
       asio::async_write(socket_, asio::buffer(message_),
                        boost::bind(&connection::handle_write, shared_from_this(),
                                    asio::placeholders::bytes_transferred));

    }

    asio::ip::tcp::socket socket_; /**< socket, associated with browser */
    asio::streambuf buf;  /**< buffer for request data */
    static std::string message_; /**< data, that we'll return to browser */
};

std::string connection::message_="HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
    "<html><head><title>test</title>"
    "</head><body><h1>Test</h1><p>This is a test!</p></body></html>";




/*
 * Simple echo server
 */
class server {
public:
/**
 * Initialize all needed data
 *
 * @param io_service reference to io_service
 * @param port port to listen on, by default - 10001
 */
    server(const ios_deque& io_services, int port=15000)
        : io_services_(io_services),
          acceptor_(*io_services.front(), /* address of the 1st elem */
                    asio::ip::tcp::endpoint(asio::ip::tcp::v4(),
                    port)) /* TCP endpoint (socket) */
                    {
        start_accept(); /* start connection accepting in asynch mode*/
    }

private:
    /**
     * start connection accepting in async mode
     *
     */
    void start_accept() {
        // select next io_service object
        io_services_.push_back(io_services_.front());
        io_services_.pop_front();
        // create new connection
        connection::pointer new_connection = connection::create(*io_services_.front());
        // start acceptor in async mode
        acceptor_.async_accept(new_connection->socket(),
                               /* handle accept = callback */
							   boost::bind(&server::handle_accept,
                            		       this,
                            		       new_connection)
								);
    }

    /**
     * Run when new connection is accepted
     *
     * @param new_connection accepted connection
     * @param error reference to error object
     */
    void handle_accept(connection::pointer new_connection)  {
            new_connection->start();
            start_accept();
    }

    ios_deque io_services_;          /**< deque of pointers to io_services */
    asio::ip::tcp::acceptor acceptor_; /**< object, that accepts new connections */
};


class test{
 void* data;
};

class test2: test{
	char* data;
};




int main(int argc, char** argv) {

	int thread_num = 1; /* number of threads */

	std::cerr<<"Start "<<thread_num<<" processes \n";
	/* container for easy handling a group of threads */
	boost::thread_group thr_grp;

	ios_deque io_services; /* list of io_service */

	/* constructor to notify io_service that work is starting*/
	std::deque<asio::io_service::work> io_service_work;

	// create threads for each io_service
     for (int i = 0; i < thread_num; ++i) {
         io_service_ptr ios(new asio::io_service); /* create */
         io_services.push_back(ios); /* add to list*/
         io_service_work.push_back(asio::io_service::work(*ios));
         // run io_service in their own thread
         thr_grp.create_thread(boost::bind(&asio::io_service::run, ios));
     }

	server echo_server(io_services); /* echo server */

    // wait until all thread will finished
    thr_grp.join_all();


    std::cerr<<"Finish.";
	return 0;
}
